package watcher

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/go-git/go-git/v5"
)

//go-git/v5 实时监听文件修改

type GitWatcher struct {
	repo     *git.Repository
	watcher  *fsnotify.Watcher
	interval time.Duration
}

/**	监听项目路径下的所有文件，并实时监听文件修改，并检查Git仓库的状态。
 *	如果文件被修改，则输出文件名和修改类型。
 *	如果Git仓库的状态发生变化，则输出文件名和状态。
 *  repoPath string 项目路径
 */
func NewGitWatcher(repoPath string, pollInterval time.Duration) (*GitWatcher, error) {
	repo, err := git.PlainOpen(repoPath)
	if err != nil {
		return nil, err
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	return &GitWatcher{
		repo:     repo,
		watcher:  watcher,
		interval: pollInterval,
	}, nil
}

func (gw *GitWatcher) Watch() {
	// 启动文件系统监听
	go gw.watchFilesystem()
	// 启动定期状态检查
	go gw.pollGitStatus()

	// 阻塞主goroutine
	select {}
}

func (gw *GitWatcher) watchFilesystem() {
	repoPath, _ := filepath.Abs(".")

	err := filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() && !shouldIgnoreDir(path) {
			return gw.watcher.Add(path)
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}

	for {
		select {
		case event, ok := <-gw.watcher.Events:
			if !ok {
				return
			}
			if event.Op&fsnotify.Write == fsnotify.Write {
				fmt.Printf("[FS] 文件修改: %s\n", event.Name)
			}
		case err, ok := <-gw.watcher.Errors:
			if !ok {
				return
			}
			log.Println("监听错误:", err)
		}
	}
}

func (gw *GitWatcher) pollGitStatus() {
	worktree, err := gw.repo.Worktree()
	if err != nil {
		log.Fatal(err)
	}

	lastStatus, _ := worktree.Status()

	ticker := time.NewTicker(gw.interval)
	defer ticker.Stop()

	for range ticker.C {
		currentStatus, err := worktree.Status()
		if err != nil {
			log.Println("获取Git状态失败:", err)
			continue
		}

		for file, status := range currentStatus {
			if lastStatus[file] != status {
				fmt.Printf("[Git] 文件变化: %s (状态: %v)\n", file, status.Worktree)
			}
		}

		lastStatus = currentStatus
	}
}

func shouldIgnoreDir(path string) bool {
	// 忽略.git目录和其他不需要监听的目录
	ignoreDirs := []string{".git", "vendor", "node_modules"}
	for _, dir := range ignoreDirs {
		if filepath.Base(path) == dir {
			return true
		}
	}
	return false
}

/* func main() {
	watcher, err := NewGitWatcher(".", 5*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	watcher.Watch()
}
*/
